﻿using System.Globalization;
using Autofac.Extensions.DependencyInjection;
using Autofac;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json.Serialization;
using System.Text;
using WkHtmlToPdfDotNet.Contracts;
using WkHtmlToPdfDotNet;
using System.ComponentModel.DataAnnotations;
using System.Reflection;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Zero.WebAPI.Framework.Filter;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Hosting;
using Zero.WebAPI.Framework.Helper;
using Zero.WebAPI.Framework.Extention;
using SqlSugar;
using Zero.WebAPI.Framework.ConfigModel;
using Zero.WebAPI.Framework.DAL;
using Zero.WebAPI.Framework.Security;


namespace Zero.WebAPI.Framework
{
    public class Startup
    {
        static Startup()
        {
            // 解决在不同平台下日期格式不一致问题
            CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("zh-CN", true) 
            {
                DateTimeFormat = new DateTimeFormatInfo() 
                {
                    ShortDatePattern = "yyyy-MM-dd", 
                    FullDateTimePattern = "yyyy-MM-dd HH:mm:ss" 
                }
            };
        }

        public WebApplication App { get; private set; }
        public WebApplicationBuilder Builder { get; }
        public IWebHostEnvironment Environment { get; }

        public Startup(WebApplicationBuilder builder)
        {
            Builder = builder;
            Environment = builder.Environment;
        }

        public void ConfigureServices(List<string> assemblyNames)
        {
            // 添加配置文件（包括环境特定配置）
            // 通过这种方式指定环境变量 set ASPNETCORE_ENVIRONMENT=Development,或在服务启动文件中配置
            Builder.Configuration
                .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                .AddJsonFile($"appsettings.{Builder.Environment.EnvironmentName}.json", optional: true, reloadOnChange: true);
            var configuration = Builder.Configuration;

            #region 动态配置启动端口
            Builder.WebHost.UseUrls(configuration["Urls"]);
            #endregion

            // 替换默认的 ServiceProviderFactory 为 Autofac
            Builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());

            Builder.Services
                .AddControllers(options =>
                {
                    options.Filters.Add<AuthInterceptor>();
                    options.Filters.Add<PermissionInterceptor>();
                })
                .AddNewtonsoftJson(options =>
                {
                    options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
                    options.SerializerSettings.ContractResolver = new DefaultContractResolver();
                    options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
                });

            // 保证service层也能够通过HttpContextAccessor访问HttpContext
            Builder.Services.AddHttpContextAccessor(); 

            Builder.Services.AddEndpointsApiExplorer();
            Builder.Services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new() { Title = "My API", Version = "v1" });

                // 添加 JWT Bearer 定义
                c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                {
                    Description = "请输入JWT令牌，格式：Bearer {token}",
                    Name = "Authorization",
                    In = ParameterLocation.Header,
                    Type = SecuritySchemeType.Http,
                    Scheme = "bearer",
                    BearerFormat = "JWT"
                });

                // 添加全局认证要求
                c.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference
                            {
                                Type = ReferenceType.SecurityScheme,
                                Id = "Bearer"
                            }
                        },
                        Array.Empty<string>()
                    }
                });
            });

            Builder.Services.AddCors(options =>
            {
                options.AddPolicy("cors", Builder =>
                {
                    Builder.WithOrigins("*")
                    .AllowAnyHeader()
                    .AllowAnyMethod();
                });
            });
            Builder.Services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(options =>
            {
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuer = true,
                    ValidateAudience = true,
                    ValidateLifetime = true,
                    ValidateIssuerSigningKey = true,
                    ValidIssuer = configuration["Jwt:Issuer"],
                    ValidAudience = configuration["Jwt:Audience"],
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["Jwt:Key"]))
                };
            });
            Builder.Logging.AddLog4Net("log4net.config");
            Builder.Logging.SetMinimumLevel(LogLevel.Information);

            // 添加缓存
            Builder.Services.AddMemoryCache();

            // 使用 Autofac 容器注册服务
            Builder.Host.ConfigureContainer<ContainerBuilder>(containerBuilder =>
            {
                // 实例注入
                containerBuilder.RegisterInstance<IConverter>(new SynchronizedConverter(new PdfTools()));

                // 配置注入
                var connectionConfigs = GetConnectionConfig(Builder.Configuration);
                containerBuilder.Register(c =>
                {
                    return new SugarDbContext(connectionConfigs,
                    db =>
                    {
                        db.Aop.OnLogExecuting = (sql, args) =>
                        {
                            ConsoleColor bakColor = Console.ForegroundColor;
                            Console.ForegroundColor = ConsoleColor.Green;
                            Console.Write("SqlSugar Log: ");
                            Console.ForegroundColor = bakColor;

                            Console.WriteLine(sql);
                            List<string> paras = args.Select(p => $"{p.ParameterName}: {p.Value}").ToList();
                            string paraStr = string.Join(',', paras);
                            Console.WriteLine($"params Info: {paraStr}");
                        };

                    });
                }).InstancePerLifetimeScope();
                containerBuilder.Register(c =>
                {
                    return new Repository(connectionConfigs, (sql, args) =>
                    {
                        ConsoleColor bakColor = Console.ForegroundColor;
                        Console.ForegroundColor = ConsoleColor.Green;
                        Console.Write("SqlSugar Log: ");
                        Console.ForegroundColor = bakColor;

                        Console.WriteLine(sql);
                        List<string> paras = args.Select(p => $"{p.ParameterName}: {p.Value}").ToList();
                        string paraStr = string.Join(',', paras);
                        Console.WriteLine($"params Info: {paraStr}");
                    });
                }).As<IRepository>().InstancePerLifetimeScope();

                // 权限认证接口单独注入
                containerBuilder.RegisterType<PermissionService>().As<IPermissionService>().InstancePerLifetimeScope();


                // 注册程序集所有的服务（例如 Service 层）
                // containerBuilder.RegisterAssemblyTypes(typeof(Program).Assembly).AsImplementedInterfaces();
                RegisterAssemblyTypes(containerBuilder,assemblyNames);

                // 注册回调，当build容器的时候进行回调，将容器设置为
                containerBuilder.RegisterBuildCallback(scope =>
                {
                    IOCHelper.SetContainer((IContainer)scope);  // 这里是父类强转成子类
                });
            });
        }

        private void RegisterAssemblyTypes(ContainerBuilder containerBuilder,List<string> assemblyNames)
        {
            if (assemblyNames == null || assemblyNames.Count == 0) return;

            foreach (var assemblyName in assemblyNames) 
            {
                Assembly assembly = Assembly.Load(assemblyName);
                // 程序集 Web.App.IService存放所有的接口,Web.App.Service存放所有的接口实现类
                // 这里需要注意：
                //      RegisterAssemblyTypes 会自动匹配实现类所实现的接口，如果接口定义在另一个程序集（如 Web.App.IService）中，只需要保证两个程序集都被引用即可。
                //      .AsImplementedInterfaces()	自动匹配它实现的接口
                containerBuilder.RegisterAssemblyTypes(assembly)
                    .Where(type => type.IsClass && !type.IsAbstract)
                    .AsImplementedInterfaces()
                    .SingleInstance();
            }
        }

        public void Run()
        {
            App = Builder.Build();

            if (App.Environment.IsDevelopment())
            {
                App.UseSwagger();
                App.UseSwaggerUI();
            }

            App.UseCors("cors");
            App.UseExceptionHandle();
            App.UseEncrypt();

            App.UseAuthorization();
            App.UseStaticFiles();
            App.MapControllers();
            App.Run();
        }

        private List<ConnectionConfig> GetConnectionConfig(ConfigurationManager configuration)
        {
            List<SqlConnectionInfo> conns = configuration.GetSection("ConnectionList").Get<List<SqlConnectionInfo>>();
            List<ConnectionConfig> connectionConfigs = new List<ConnectionConfig>();
            foreach (var conn in conns)
            {
                connectionConfigs.Add(new ConnectionConfig()
                {
                    ConfigId = conn.ConfigId,
                    ConnectionString = conn.ConnectionString,
                    DbType = Enum.Parse<DbType>(conn.DbType),
                    IsAutoCloseConnection = conn.IsAutoCloseConnection,
                    ConfigureExternalServices = new ConfigureExternalServices
                    {
                        //注意:  这儿AOP设置不能少
                        EntityService = (c, p) =>
                        {
                            /***低版本C#写法***/
                            // int?  decimal?这种 isnullable=true,string类型需要特别处理
                            if (p.IsPrimarykey)
                            {
                                p.IsNullable = false;
                            }
                            else if (c.PropertyType.IsGenericType && c.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                            {
                                p.IsNullable = true;
                            }
                            else if (c.PropertyType == typeof(string))
                            {
                                if (c.GetCustomAttribute<RequiredAttribute>() == null)
                                    p.IsNullable = true;
                            }
                        }
                    }
                });
            }
            return connectionConfigs;
        }
    }
}
